"""
衍生品标的指数模块
获取衍生品的标的指数列表
"""
import time
from typing import Dict, List, Optional
from datetime import datetime, timedelta
from loguru import logger

try:
    import okx.PublicData as PublicData
except ImportError:
    logger.warning("okx SDK未安装，请运行: pip install okx")
    PublicData = None


class UnderlyingManager:
    """衍生品标的指数管理器"""
    
    # 限速配置：20次/2s
    RATE_LIMIT_REQUESTS = 20
    RATE_LIMIT_WINDOW = 2.0  # 秒
    
    def __init__(self, sandbox: bool = True):
        """
        初始化衍生品标的指数管理器
        
        Args:
            sandbox: 是否使用模拟盘，True=模拟盘(1)，False=实盘(0)
        """
        if PublicData is None:
            raise ImportError("okx SDK未安装，请运行: pip install okx")
        
        self.sandbox = sandbox
        flag = "1" if sandbox else "0"
        
        # 初始化OKX公共数据API
        self.public_api = PublicData.PublicAPI(flag=flag)
        
        # 限速控制
        self.request_times: List[float] = []  # 请求时间戳列表
        
        # 数据缓存
        self.underlying_cache: Dict[str, List[str]] = {}  # inst_type -> underlying_list
        self.cache_expire_time: Dict[str, datetime] = {}  # inst_type -> expire_time
        self.cache_duration = timedelta(hours=24)  # 缓存24小时
        
        logger.info(f"衍生品标的指数管理器已初始化 (模式: {'模拟盘' if sandbox else '实盘'})")
    
    def _check_rate_limit(self):
        """
        检查并执行限速
        限速规则：20次/2s (IP)
        """
        now = time.time()
        
        # 移除2秒前的请求记录
        self.request_times = [t for t in self.request_times 
                             if now - t < self.RATE_LIMIT_WINDOW]
        
        # 如果达到限速上限，等待
        if len(self.request_times) >= self.RATE_LIMIT_REQUESTS:
            oldest_request = self.request_times[0]
            wait_time = self.RATE_LIMIT_WINDOW - (now - oldest_request)
            
            if wait_time > 0:
                logger.debug(f"触发限速，等待 {wait_time:.2f} 秒")
                time.sleep(wait_time)
                # 重新计算
                now = time.time()
                self.request_times = [t for t in self.request_times 
                                     if now - t < self.RATE_LIMIT_WINDOW]
        
        # 记录本次请求
        self.request_times.append(now)
    
    def get_underlying(self, inst_type: str, use_cache: bool = True) -> List[str]:
        """
        获取衍生品标的指数
        
        Args:
            inst_type: 产品类型
                - SWAP: 永续合约
                - FUTURES: 交割合约
                - OPTION: 期权
            use_cache: 是否使用缓存
            
        Returns:
            标的指数列表，如 ['BTC-USD', 'ETH-USD', ...]
        """
        # 检查缓存
        if use_cache and inst_type in self.underlying_cache:
            expire_time = self.cache_expire_time.get(inst_type)
            if expire_time and datetime.now() < expire_time:
                logger.debug(f"从缓存获取标的指数: {inst_type}")
                return self.underlying_cache[inst_type]
        
        # 执行限速检查
        self._check_rate_limit()
        
        try:
            logger.info(f"获取衍生品标的指数: {inst_type}")
            result = self.public_api.get_underlying(instType=inst_type)
            
            # 检查响应
            if result.get("code") != "0":
                error_msg = result.get("msg", "未知错误")
                logger.error(f"获取标的指数失败: {error_msg}")
                raise RuntimeError(f"API错误: {error_msg}")
            
            # 提取数据
            data_list = result.get("data", [])
            underlying_list = [item for item in data_list if item]  # 过滤空值
            logger.info(f"获取标的指数成功: {len(underlying_list)} 个标的")
            
            # 更新缓存
            if use_cache:
                self.underlying_cache[inst_type] = underlying_list
                self.cache_expire_time[inst_type] = datetime.now() + self.cache_duration
            
            return underlying_list
            
        except Exception as e:
            logger.error(f"获取标的指数异常: {e}")
            raise
    
    def get_swap_underlying(self, use_cache: bool = True) -> List[str]:
        """
        获取永续合约标的指数
        
        Args:
            use_cache: 是否使用缓存
            
        Returns:
            永续合约标的指数列表
        """
        return self.get_underlying("SWAP", use_cache)
    
    def get_futures_underlying(self, use_cache: bool = True) -> List[str]:
        """
        获取交割合约标的指数
        
        Args:
            use_cache: 是否使用缓存
            
        Returns:
            交割合约标的指数列表
        """
        return self.get_underlying("FUTURES", use_cache)
    
    def get_option_underlying(self, use_cache: bool = True) -> List[str]:
        """
        获取期权标的指数
        
        Args:
            use_cache: 是否使用缓存
            
        Returns:
            期权标的指数列表
        """
        return self.get_underlying("OPTION", use_cache)
    
    def get_all_underlying(self) -> Dict[str, List[str]]:
        """
        获取所有产品类型的标的指数
        
        Returns:
            字典，key为产品类型，value为标的指数列表
        """
        inst_types = ["SWAP", "FUTURES", "OPTION"]
        all_underlying = {}
        
        for inst_type in inst_types:
            try:
                underlying_list = self.get_underlying(inst_type)
                all_underlying[inst_type] = underlying_list
            except Exception as e:
                logger.error(f"获取 {inst_type} 标的指数失败: {e}")
                all_underlying[inst_type] = []
        
        return all_underlying
    
    def get_base_currencies(self, inst_type: str = "SWAP") -> List[str]:
        """
        获取基础货币列表（从标的指数中提取）
        
        Args:
            inst_type: 产品类型
            
        Returns:
            基础货币列表，如 ['BTC', 'ETH', ...]
        """
        underlying_list = self.get_underlying(inst_type)
        
        # 从标的指数中提取基础货币（如 BTC-USD -> BTC）
        base_currencies = set()
        for uly in underlying_list:
            if "-" in uly:
                base_ccy = uly.split("-")[0]
                base_currencies.add(base_ccy)
        
        return sorted(list(base_currencies))
    
    def get_quote_currencies(self, inst_type: str = "SWAP") -> List[str]:
        """
        获取计价货币列表（从标的指数中提取）
        
        Args:
            inst_type: 产品类型
            
        Returns:
            计价货币列表，如 ['USD', 'USDT', ...]
        """
        underlying_list = self.get_underlying(inst_type)
        
        # 从标的指数中提取计价货币（如 BTC-USD -> USD）
        quote_currencies = set()
        for uly in underlying_list:
            if "-" in uly:
                quote_ccy = uly.split("-")[1]
                quote_currencies.add(quote_ccy)
        
        return sorted(list(quote_currencies))
    
    def filter_by_base_currency(self, base_ccy: str, inst_type: str = "SWAP") -> List[str]:
        """
        按基础货币过滤标的指数
        
        Args:
            base_ccy: 基础货币，如 BTC
            inst_type: 产品类型
            
        Returns:
            匹配的标的指数列表
        """
        underlying_list = self.get_underlying(inst_type)
        
        filtered = [uly for uly in underlying_list if uly.startswith(f"{base_ccy}-")]
        
        return filtered
    
    def filter_by_quote_currency(self, quote_ccy: str, inst_type: str = "SWAP") -> List[str]:
        """
        按计价货币过滤标的指数
        
        Args:
            quote_ccy: 计价货币，如 USD
            inst_type: 产品类型
            
        Returns:
            匹配的标的指数列表
        """
        underlying_list = self.get_underlying(inst_type)
        
        filtered = [uly for uly in underlying_list if uly.endswith(f"-{quote_ccy}")]
        
        return filtered
    
    def get_underlying_stats(self) -> Dict:
        """
        获取标的指数统计信息
        
        Returns:
            统计信息字典
        """
        all_underlying = self.get_all_underlying()
        
        stats = {
            "total_by_type": {},
            "total_unique": 0,
            "base_currencies": set(),
            "quote_currencies": set(),
        }
        
        all_unique = set()
        
        for inst_type, underlying_list in all_underlying.items():
            stats["total_by_type"][inst_type] = len(underlying_list)
            all_unique.update(underlying_list)
            
            # 提取基础货币和计价货币
            for uly in underlying_list:
                if "-" in uly:
                    parts = uly.split("-")
                    stats["base_currencies"].add(parts[0])
                    if len(parts) > 1:
                        stats["quote_currencies"].add(parts[1])
        
        stats["total_unique"] = len(all_unique)
        stats["base_currencies"] = sorted(list(stats["base_currencies"]))
        stats["quote_currencies"] = sorted(list(stats["quote_currencies"]))
        
        return stats
    
    def clear_cache(self, inst_type: Optional[str] = None):
        """
        清除缓存
        
        Args:
            inst_type: 产品类型，如果为None则清除所有缓存
        """
        if inst_type:
            if inst_type in self.underlying_cache:
                del self.underlying_cache[inst_type]
            if inst_type in self.cache_expire_time:
                del self.cache_expire_time[inst_type]
            logger.info(f"已清除 {inst_type} 的缓存")
        else:
            self.underlying_cache.clear()
            self.cache_expire_time.clear()
            logger.info("已清除所有标的指数缓存")
    
    def get_cache_stats(self) -> Dict:
        """
        获取缓存统计信息
        
        Returns:
            缓存统计字典
        """
        total_cached = len(self.underlying_cache)
        valid_cached = sum(1 for inst_type in self.underlying_cache.keys()
                          if inst_type in self.cache_expire_time and
                          datetime.now() < self.cache_expire_time[inst_type])
        
        return {
            "total_cached": total_cached,
            "valid_cached": valid_cached,
            "expired_cached": total_cached - valid_cached,
            "cache_duration_hours": self.cache_duration.total_seconds() / 3600,
        }


# 便捷函数
def get_underlying(inst_type: str, sandbox: bool = True) -> List[str]:
    """
    便捷函数：获取衍生品标的指数
    
    Args:
        inst_type: 产品类型 (SWAP/FUTURES/OPTION)
        sandbox: 是否使用模拟盘
        
    Returns:
        标的指数列表
    """
    manager = UnderlyingManager(sandbox=sandbox)
    return manager.get_underlying(inst_type)


def get_base_currencies(inst_type: str = "SWAP", sandbox: bool = True) -> List[str]:
    """
    便捷函数：获取基础货币列表
    
    Args:
        inst_type: 产品类型
        sandbox: 是否使用模拟盘
        
    Returns:
        基础货币列表
    """
    manager = UnderlyingManager(sandbox=sandbox)
    return manager.get_base_currencies(inst_type)


def get_underlying_stats(sandbox: bool = True) -> Dict:
    """
    便捷函数：获取标的指数统计信息
    
    Args:
        sandbox: 是否使用模拟盘
        
    Returns:
        统计信息字典
    """
    manager = UnderlyingManager(sandbox=sandbox)
    return manager.get_underlying_stats()
